﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Microsoft.Office.Interop.Word;


namespace WordRegexAddIn
{
    class RegexFinder
    {

        public Microsoft.Office.Interop.Word.Application App { get; private set; }

        /// <summary>
        /// 正则表达式
        /// </summary>
        public string Pattern { get; set; }

        /// <summary>
        /// 替换内容
        /// </summary>
        public string Replacement { get; set; }

        public RegexOptions Options;

        public bool IgnoreCase
        {
            get { return (Options & RegexOptions.IgnoreCase) == RegexOptions.IgnoreCase; }
            set {
                if (value)
                {
                    Options |= RegexOptions.IgnoreCase;
                }
                else
                {
                    Options &=~ RegexOptions.IgnoreCase;
                }
            }
        }

        private Regex RegIns;

        private int matchStart;
        private Match match;

        private Document Doc;
        private Selection Selection;
        private Range SelecRange;

        public RegexFinder(Microsoft.Office.Interop.Word.Application app)
        {
            App = app;
            app.DocumentOpen += App_DocumentOpen;
            
        }

        

        private void App_DocumentOpen(Document Doc)
        {
            this.Doc = Doc;
            this.Selection = App.Selection;
        }




        /// <summary>
        /// 光标在以WdUnits.wdCharacter(字符)单位移动过程中会忽略 '\a'计数,
        /// 所以在光标位置转换到实际字符位置是需要将'\a'的数量补充上.
        /// </summary>
        /// <param name="wdPoint"></param>
        /// <returns></returns>
        int wd2reg(int wdPoint)
        {
            string txt = Doc.Content.Text;
            for (var i = 0; i < wdPoint; i++)
            {
                if (txt[i] == '\a')
                {
                    wdPoint += 1;
                }
            }
            return wdPoint;
        }

        /// <summary>
        /// 光标在以WdUnits.wdCharacter(字符)单位移动过程中会忽略 '\a'计数,
        /// 所以在实际字符位置转换到光标位置是需要将'\a'的数量去除.
        /// </summary>
        /// <param name="regPoint"></param>
        /// <returns></returns>
        int reg2wd(int regPoint)
        {
            string txt = Doc.Content.Text;
            for (var i = 0; i < regPoint; i++)
            {
                if (txt[i] == '\a')
                {
                    regPoint -= 1;
                }

            }
            return regPoint;
        }

        


        /// <summary>
        /// 
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        private bool SelectMatch(Match match)
        {
            if (match.Success)
            {
                //var tmp = Doc.Content.Text.Substring(matchStart, match.Index - matchStart);
                //log.println(tmp);
                Selection.MoveStart(WdUnits.wdCharacter, reg2wd(match.Index) - Selection.Start);//- Selection.Start
                Selection.End = Selection.Start;
                Selection.MoveEnd(WdUnits.wdCharacter, match.Length);
                SelecRange = Selection.Range;
                SelecRange.Select();
                return true;
            }
            SelecRange = null;
            return false;
        }

        /// <summary>
        /// 查找下一个
        /// </summary>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public Range Find(string pattern)
        {
            if (string.IsNullOrEmpty(pattern)) return null;

            Options &= ~RegexOptions.RightToLeft;
            if (!pattern.Equals(this.Pattern) || RegIns == null || RegIns.Options  != Options)
            {
                
                this.Pattern = pattern;
                RegIns = new Regex(this.Pattern,Options);
                
            }
            if (RegIns != null)
            {
                
                matchStart = wd2reg(Math.Max(Selection.Start, Selection.End));
                match = RegIns.Match(Doc.Content.Text, matchStart);
                if (!SelectMatch(match))
                {
                    if (matchStart == 0)
                    {
                        RegIns = null;
                        match = null;
                        MessageBox.Show("没有找到比配内容.", "正则表达式");
                        return null;
                    }
                    matchStart = 0;
                    match = RegIns.Match(Doc.Content.Text, matchStart);
                    if (!SelectMatch(match))
                    {
                        RegIns = null;
                        match = null;
                        MessageBox.Show("没有找到比配内容.", "正则表达式");
                        return null;
                    }
                }

            }
            else
            {
                return null;
            }

            return Selection.Range;
        }


        public Range Find(int regStart,int regEnd)
        {
            var match=RegIns.Match(Doc.Content.Text, regStart, regEnd);
            

            return null;
        }

        /// <summary>
        /// 查找上一个
        /// </summary>
        /// <returns></returns>
        public Range Previous(string pattern)
        {
            if (string.IsNullOrEmpty(pattern)) return null;
            Options |= RegexOptions.RightToLeft;
            if (!pattern.Equals(this.Pattern) || RegIns == null|| RegIns.Options != Options)
            {
          
                this.Pattern = pattern;
                RegIns = RegIns = new Regex(this.Pattern, Options);
            }

            if (RegIns != null)
            {

                matchStart = wd2reg(Math.Min(Selection.Start, Selection.End));
                match = RegIns.Match(Doc.Content.Text, matchStart);
                if (!SelectMatch(match))
                {
                    if (matchStart == Doc.Content.Text.Length)
                    {
                        RegIns = null;
                        match = null;
                        MessageBox.Show("没有找到比配内容.", "正则表达式");
                        return null;
                    }
                    matchStart = Doc.Content.Text.Length;
                    match = RegIns.Match(Doc.Content.Text, matchStart);
                    if (!SelectMatch(match))
                    {
                        RegIns = null;
                        match = null;
                        MessageBox.Show("没有找到比配内容.", "正则表达式");
                        return null;
                    }
                }

            }
            else
            {
                return null;
            }

            return Selection.Range;
        }


        public void Replace(string pattern, string replacement)
        {
            if (!String.IsNullOrEmpty(pattern)) return;
            this.Pattern = pattern;
            this.Replacement = replacement;
            if (SelecRange == null)
            {
                Find(Pattern);
            }
            else
            {
                SelecRange.Text = RegIns.Replace(SelecRange.Text, replacement);
                Find(Pattern);
            }
        }

        public void ReplaceAll(string pattern, string replacement)
        {
            if (String.IsNullOrEmpty(pattern)) return;
            this.Pattern = pattern;
            this.Replacement = replacement;
            int count = 0;
            RegexOptions opt = this.IgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
            int start = 0;
            RegIns = new Regex(pattern, opt);
            while (true)
            {
                var match= RegIns.Match(Doc.Content.Text,start);
                if (!match.Success) break;
                
                var range = Doc.Range(reg2wd(match.Index),reg2wd(match.Index+match.Length));
                //System.Diagnostics.Debug.WriteLine(range.Text);
                range.Text=RegIns.Replace(range.Text, replacement);
                start = wd2reg(range.End);
                count++;
               
            }
            MessageBox.Show($"成功替换了{count}个比配到的内容.", "正则表达式");
        }


        


    }
}
